<?php
// +----------------------------------------------------------------------
// | WokrFlow 工作流服务
// +----------------------------------------------------------------------
// | 主要服务于WorkFlow工作流数据处理
// +----------------------------------------------------------------------
// | 错误编码头 242xxx
// +----------------------------------------------------------------------

namespace common\service;

use common\exception\LogicException;
use common\model\AttributeModel;
use common\model\ProjectModel;
use common\model\ReviewFeedbackModel;
use common\model\StageModel;
use common\model\StepCategoryModel;
use common\model\StepModel;
use common\model\StepWorkflowModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;

class StepWorkflowService
{


    // 单例工具
    use SingletonTrait;

    /**
     * 获得单个工作流
     * @param $workflowId
     * @param $field
     * @return mixed
     */
    public function getStepWorkFlow($workflowId, $field)
    {
        $stepWorkflowModel = model(StepWorkflowModel::class);
        $stepWorkflow = $stepWorkflowModel->where(['id' => $workflowId])
            ->field($field)
            ->find();
        return $stepWorkflow;
    }

    /**
     * 获得多个工作流
     * @param $workflowId
     * @param $field
     * @return mixed
     */
    public function getStepWorkFlows($workflowId, $field)
    {
        $stepWorkflowModel = model(StepWorkflowModel::class);
        $stepWorkflow = $stepWorkflowModel->where(['id' => $workflowId])
            ->field($field)
            ->select();
        return $stepWorkflow;
    }

    /**
     * 自动检查工序流数据
     * @return array
     */
    public function autoFixConfig()
    {
        $stepModel = model(StepModel::class);
        $stepWorkFlowModel = model(StepWorkflowModel::class);
        $stepCategoryModel = model(StepCategoryModel::class);
        $rows = $stepWorkFlowModel->select();
        $res = [];

        //处理工序数据
        foreach ($rows as &$flow) {
            $config = json_decode($flow['config'], true);

            if (!array_key_exists('edges', $config) || !array_key_exists('nodes', $config)) {
                continue;
            }
            $relations = $config['edges'];
            $changedNodeIdData = []; //用来替换edges 里的连线数据
            $changedMap = []; //用来返回对比
            $needChange = false;

            //遍历nodes
            foreach ($config['nodes'] as &$node) {
                foreach ($node as &$step) {
                    $stepFromDatabase = $stepModel->where(['code' => $step['module_code']])->find();
                    if (empty($stepFromDatabase)) {
                        // 找不到该工序
                        // 工序里标记为异常  清空配置 continue 3
                        $res['is_abnormal'][] = $stepWorkFlowModel->modifyItem([
                            'id' => $flow['id'],
                            'is_abnormal' => "yes",
                            'config' => [],
                        ]);
                        $res['message'][] = "can`t found step {$step['module_code']}";
                        continue 3;
                    }

                    $stepCategory = $stepCategoryModel->find($stepFromDatabase['step_category_id']);

                    if ($step['id'] !== (string)$stepFromDatabase['id'] ||
                        $step['module_id'] !== (string)$stepFromDatabase['id'] ||
                        $step['step_category_id'] !== (string)$stepFromDatabase['step_category_id'] ||
                        $step['step_category_parent_id'] !== (string)$stepCategory['parent_id']
                    ) {
                        $needChange = true;
                        $tmpChangeMap = [
                            'old' => $step,
                        ];
                        //处理 edges 替换map
                        if ($step['id'] != $stepFromDatabase['id']) {
                            $changedNodeIdData[$step['id']] = ['from' => (string)$step['id'], 'to' => (string)$stepFromDatabase['id']];
                        }
                        $step['id'] = (string)$stepFromDatabase['id'];
                        $step['module_id'] = (string)$stepFromDatabase['id']; //module_id  是前端使用的step_id
                        $step['step_category_id'] = (string)$stepFromDatabase['step_category_id'];
                        $step['step_category_parent_id'] = (string)$stepCategory['parent_id'];
                        $tmpChangeMap['new'] = $step;
                        $changedMap[] = $tmpChangeMap;
                    }
                }
            }

            //处理step_list

            foreach ($config['stepList'] as $key => &$stepItem) {
                $stepFromDatabase = $stepModel->where(['code' => $stepItem['code']])->find();
                if (empty($stepFromDatabase)) {
                    unset($config['stepList'][$key]);
                    continue;
                }
                $stepCategory = $stepCategoryModel->find($stepItem['step_category_id']);
                $stepCategoryParent = $stepCategoryModel->find($stepCategory['parent_id']);

                if ($stepItem['id'] !== (string)$stepFromDatabase['id'] ||
                    $stepItem['step_category_id'] !== (string)$stepFromDatabase['step_category_id'] ||
                    $stepItem['step_category_parent_id'] !== (string)$stepCategory['parent_id']
                ) {
                    $needChange = true;
                    $stepItem['id'] = (string)$stepFromDatabase['id'];
                    $stepItem['step_category_id'] = (string)$stepFromDatabase['step_category_id'];
                    $stepItem['step_category_parent_id'] = (string)$stepCategory['parent_id'];
                    $stepItem['name'] = (string)$stepFromDatabase['name'];
                    $stepItem['step_category_name'] = (string)$stepCategory['name'];
                    $stepItem['step_category_parent_name'] = (string)$stepCategoryParent['name'];
                }
            }
            $config['stepList'] = array_values($config['stepList']);

            //处理edge
            $relations = array_map(function (&$item) use ($changedNodeIdData, &$needChange) {
                $sourceReplace = false;
                $targetReplace = false;
                if ($item['source'] !== (string)$item['source'] || $item['target'] !== (string)$item['target']) {
                    $needChange = true;
                }
                $item['source'] = (string)$item['source'];
                $item['target'] = (string)$item['target'];

                foreach ($changedNodeIdData as $changeItem) {
                    if ($item['source'] == $changeItem['from'] && !$sourceReplace) {
                        $item['source'] = $changeItem['to'];
                        $sourceReplace = true;
                        $needChange = true;

                    }
                    if ($item['target'] == $changeItem['from'] && !$targetReplace) {
                        $item['target'] = $changeItem['to'];
                        $targetReplace = true;
                        $needChange = true;
                    }
                }
                return $item;
            }, $relations);

            if (!$needChange) {
                continue;
            }

            $config['edges'] = $relations;

            $changeResult = $stepWorkFlowModel->modifyItem([
                'id' => $flow['id'],
                'config' => $config,
            ]);
            if ($changeResult != false) {
                $res['fixed'][] = [
                    'after' => $changeResult,
                    'changed' => $changedMap,
                    'changeEg' => $changedNodeIdData
                ];
            } else {
                $res['error'][$flow['id']] = [
                    $stepWorkFlowModel->getError(),
                    $stepWorkFlowModel->getErrorCode(),
                ];
            }
        }

        return $res;
    }

    /**
     * 通过工序id查询工序流
     * @param $param
     * @return array
     */
    public function selectByStepId($param)
    {
        $stepWorkflow = model(StepWorkflowModel::class);

        $stepId = $param['param']['filter']['step_id'];

        $page = $param['param']['page'] ?? null;
        $fields = $param['param']['fields'] ?? "*";
        $where = "find_in_set({$stepId},json_unquote(json_extract(config,'$.stepStr')))";
        $count = $stepWorkflow->where($where)->count();

        $stepWorkflow->where($where);
        if ($page) {
            $stepWorkflow->page($page[0], $page[1]);
        } else {
            $stepWorkflow->limit(C("database.database_max_select_rowd"));
        }
        $data = $stepWorkflow->field($fields)->select();
        return [
            'total' => $count,
            'rows' => $data,
        ];
    }


    /**
     * 通过当前工序流配置，获取工序分类前后置关系
     * @param array $config
     * @return array
     */
    public function getStepCategoryRelateByStepWorkflow($config = [])
    {
        $stepCategoryPreAndPostRelation = [];

        if (array_key_exists('stepList', $config) && array_key_exists('edges', $config)) {
            // 获取工序映射字典
            $stepMap = array_column($config['stepList'], null, 'id');

            if (count($config['edges']) == 0) {
                // 当没有关系的时候 直接放进去节点

                foreach ($config['nodes'] as $nodes) {
                    foreach ($nodes as $node) {
                        $stepCategoryPreAndPostRelation[] = [
                            'from_step_category_id' => $node['step_category_id'],
                            'source' => $node['id'],
                            'pre_step_category_id' => 0 // 没有前置任务数据
                        ];
                    }
                }
            } else {
                // 判断前后置关系
                $existIds = [];
                foreach ($config['edges'] as $edge) {
                    if (empty($stepCategoryPreAndPostRelation)) {
                        // 第一个
                        $existIds[] = $stepMap[$edge['source']]['step_category_id'];
                        $stepCategoryPreAndPostRelation[] = [
                            'from_step_category_id' => $stepMap[$edge['source']]['step_category_id'],
                            'source' => $edge['source'],
                            'pre_step_category_id' => 0 // 没有前置任务数据
                        ];
                    }

                    if (!in_array($stepMap[$edge['target']]['step_category_id'], $existIds)) {
                        $preStepData = $stepMap[$edge['source']];
                        $existIds[] = $stepMap[$edge['target']]['step_category_id'];
                        $stepCategoryPreAndPostRelation[] = [
                            'from_step_category_id' => $stepMap[$edge['target']]['step_category_id'],
                            'pre_step_category_id' => $preStepData['step_category_id'],
                            'pre_step_category_name' => $preStepData['step_category_name'],
                            'pre_step_category_parent_id' => $preStepData['step_category_parent_id'],
                            'pre_step_category_parent_name' => $preStepData['step_category_parent_name']
                        ];
                    }
                }
            }


        }

        return $stepCategoryPreAndPostRelation;
    }

    /**
     * 解析出配置中的属性列表 进行交叉
     * @param $rules
     * @return array
     */
    public function getNodeConfigCombinedAttrList($rules)
    {
        $attrValList = [];
        foreach ($rules as $rule) {
            if (!isset($rule['attribute_key']) || !isset($rule['attribute_values'])) {
                continue;
            }
            $attrValList[$rule['attribute_key']] = $rule['attribute_values'];
        }
        // 排序 按照固定规则组合
        ksort($attrValList);

        // 提前排好顺序的attr keys
        $attrKeyList = array_keys($attrValList);
        // 分离出values 进行组合
        $attrValList = array_values($attrValList);

        $res = combine_dika($attrValList);
        return [$res, $attrKeyList];
    }

    /**
     * 查询工序标准目录
     * @return array
     */
    public function getWorkflowStepStandards(int $projectTemplateId)
    {
        $workflowWhere = [
            'project_template_id' => 0,
            'project_id' => 0,
        ];
        if ($projectTemplateId > 0) {
            $workflowWhere['project_template_id'] = $projectTemplateId;
            $workflowWhere['project_id'] = 0; // todo 兼容新工序流
        }
        $workflows = model(StepWorkflowModel::class)
            ->field('id,name,step_workflow_config as config,"workflow" as type')
            ->where($workflowWhere)
            ->where("step_workflow_config != ''")
            ->select();

        $stepList = model(StepModel::class)->field('id,name,code,"step" as type')->select();
        $stepList = array_column($stepList, null, 'code');

        $attributeList = model(AttributeModel::class)->select();
        $attributeMap = array_column($attributeList, null, 'code');
        $thirdLevelIndex = 0;

        foreach ($workflows as &$workflow) {
            $config = json_decode($workflow['config'], true);
            unset($workflow['config']);
            foreach ($config['nodes'] ?? [] as $nodeList) {
                foreach ($nodeList as $node) {
                    if (empty($node['module_code']) || !isset($stepList[$node['module_code']])) {
                        // 工序不存在
                        continue;
                    }
                    $tmpStepInfo = $stepList[$node['module_code']];
                    if (array_key_exists('config', $node) && count($node['config']) > 0) {
                        foreach ($node['config'] as $rules) {
                            list($res, $attrKeyList) = $this->getNodeConfigCombinedAttrList($rules);
                            foreach ($res as $attrBind) {
                                $thirdLevelIndex += 1;
                                $str = '';
                                foreach ($attrBind as $attrVK => $attrV) {
                                    $str .= $attributeMap[$attrKeyList[$attrVK]]['name'] . ":" . $attrV . '-';
                                }
                                $tmpStepInfo['children'][] = ['id' => $thirdLevelIndex, 'name' => trim($str, '-'), 'type' => 'attr_combined'];
                            }
                        }

                    }
                    $workflow['children'][] = $tmpStepInfo;
                }
            }
        }

        return $workflows;
    }

    /**
     * 生成工序流唯一数据值
     * @param $stepWorkflowId
     * @param $attributeRuleMapByCode
     * @param $attrValues
     * @param $stepId
     * @return string
     */
    public function generateWorkflowStepDocAttrStr($stepWorkflowId, $attributeRuleMapByCode, $attrValues, $stepId)
    {

        if (empty($attrValues)) {
            return '';
        }

        $workflowsData = model(StepWorkflowModel::class)->field('id,name,step_workflow_config as config')
            ->where(['id' => $stepWorkflowId])
            ->find();
        if (empty($workflowsData)) {
            throw new LogicException('stepworkflow not found', ErrorCode::TASK_WORKFLOW_CONFIG_NOT_EXIST);
        }

        $workflowsConfig = json_decode($workflowsData['config'], true);

        $useAttrKeys = [];
        foreach ($workflowsConfig['nodes'] as $nodeList) {
            foreach ($nodeList as $node) {
                if ($node['id'] == $stepId && array_key_exists('config', $node) && count($node['config']) > 0) {
                    foreach ($node['config'] as $rules) {
                        foreach ($rules as $rule) {
                            if (!in_array($rule['attribute_key'], $useAttrKeys)) {
                                $useAttrKeys[] = $rule['attribute_key'];
                            }
                        }
                    }
                }
            }
        }

        // 按照数值升序排序 按照固定规则组合
        sort($useAttrKeys);

        // 查询当前工序引用属性名称
        $attrName = model(AttributeModel::class)->field('name,code')->where(['code' => ['IN', join(',', $useAttrKeys)]])->select();
        $attrNameMap = array_column($attrName, 'name', 'code');

        // 组装
        $attrStr = '';
        foreach ($useAttrKeys as $useAttrKey) {
            // 可能这个实体 没有这个属性 那么就跳过这个属性
            if (empty($attrNameMap[$useAttrKey]) || empty($attributeRuleMapByCode[$useAttrKey]) || !array_key_exists($attributeRuleMapByCode[$useAttrKey]['field'], $attrValues)) {
                continue;
            }
            $attrStr .= $attrNameMap[$useAttrKey] . ":" . $attrValues[$attributeRuleMapByCode[$useAttrKey]['field']] . '-';
        }

        return trim($attrStr, '-');
    }

    /**
     * 查询工序流工序节点
     * @param array $stepWorkflowIds
     * @param bool $isGetStepWorkflowFields
     * @return array
     */
    public function getStepNodesDictByStepWorkflowId(array $stepWorkflowIds, $isGetStepWorkflowFields = false)
    {
        $stepWorkflowFields = [
            "id",
            "JSON_UNQUOTE(JSON_EXTRACT(step_workflow_config,'$.nodes')) as step_workflow_config_nodes",
            "JSON_UNQUOTE(JSON_EXTRACT(step_workflow_config,'$.edges')) as step_workflow_config_edges",
            "project_id"
        ];
        $workflowData = model(StepWorkflowModel::class)
            ->where(['id' => ['in', implode(',', $stepWorkflowIds)]])
            ->field($stepWorkflowFields)
            ->select();
        $stepsInfo = model(StepModel::class)->select();
        $stepsInfo = array_column($stepsInfo, null, 'id');
        $res = [];
        foreach ($workflowData as $workFlow) {
            $workFlowNodes = json_decode($workFlow['step_workflow_config_nodes'] ?? '{}', true);
            $workFlowEdges = json_decode($workFlow['step_workflow_config_edges'] ?? '{}', true);
            $stepIds = [];
            $currentExistStepList = [];
            foreach ($workFlowNodes as $key => &$node) {
                if (empty($node)) {
                    unset($workFlowNodes[$key]);
                }
                foreach ($node as $nodeItem) {
                    $stepIds[$nodeItem['step_category_id']][] = $nodeItem['id'];
                    if (array_key_exists($nodeItem['id'], $stepsInfo)) {
                        $currentExistStepList[] = $nodeItem['id'];
                    }
                }
            }
            $res[$workFlow['id']] = [
                'step_id_list' => $currentExistStepList,
                "steps" => $stepIds,
                "nodes" => $workFlowNodes,
                "edges" => $workFlowEdges,
            ];
        }

        foreach ($res as &$workflowConfig) {
            foreach ($workflowConfig['nodes'] as &$nodes) {
                // 过滤工序流配置里不存在的工序
                $nodes = array_filter($nodes, function ($node) use ($stepsInfo) {
                    return array_key_exists($node['id'], $stepsInfo);
                });
                $nodes = array_map(function ($node) use (&$stepsInfo) {
                    return array_merge($node, $stepsInfo[$node['id']]);
                }, $nodes);
            }
        }

        return $res;
    }

    /**
     * 通过工序流程ID组装工序分类列表字典
     * @param $stepWorkflowIds
     * @return array
     */
    public function getStepCategoryDictByStepWorkflowId($stepWorkflowIds)
    {
        // 获取step_category_id
        $stepWorkflowData = model(StepWorkflowModel::class)
            ->field('id,step_category_id,config,step_workflow_config,module_id')
            ->where(['id' => ['IN', join(',', $stepWorkflowIds)]])
            ->select();
        $stepCategoryDictByStepWorkflowId = [];
        if (!empty($stepWorkflowData)) {
            $stepWorkflowCategoryDict = [];
            $stepWorkflowConfigDict = [];
            $moduleIds = [];

            foreach ($stepWorkflowData as $item) {
                $stepWorkflowCategoryDict[$item['id']] = $item['module_id'];
                $stepWorkflowConfigDict[$item['id']] = !empty($item['step_workflow_config']) ? json_decode($item['step_workflow_config'], true) : [];
                if (!in_array($item['module_id'], $moduleIds)) {
                    $moduleIds[] = $item['module_id'];
                }
            }
            if (!empty($moduleIds)) {
                // 找到当前分类下面的儿子
                $stepCategoryModel = model(StepCategoryModel::class);
                $stepCategoryData = $stepCategoryModel->field('id,parent_id,name,code')->where(['parent_id' => ['IN', join(',', $moduleIds)]])->select();
                $stepCategoryDict = [];

                if (!empty($stepCategoryData)) {
                    foreach ($stepCategoryData as $stepCategoryItem) {
                        if (array_key_exists($stepCategoryItem['parent_id'], $stepCategoryDict)) {
                            $stepCategoryDict[$stepCategoryItem['parent_id']][] = $stepCategoryItem;
                        } else {
                            $stepCategoryDict[$stepCategoryItem['parent_id']] = [
                                $stepCategoryItem
                            ];
                        }
                    }

                    // 映射回主表
                    foreach ($stepWorkflowCategoryDict as $stepWorkflowId => $moduleId) {
                        $stepCategoryTemp['step_category_data'] = array_column($stepCategoryDict[$moduleId], null, 'id');
                        $stepCategoryTemp['pre_and_post_relation'] = $this->getStepCategoryRelateByStepWorkflow($stepWorkflowConfigDict[$stepWorkflowId]);
                        $stepCategoryDictByStepWorkflowId[$stepWorkflowId] = $stepCategoryTemp;
                    }
                }
            }
        }

        return $stepCategoryDictByStepWorkflowId;
    }

    /**
     * 匹配工序属性 检测是否需要生成
     * @param $moduleCode
     * @param array $node
     * @param array $notGeneratedEntityItem
     * @return bool
     */
    public function matchNodeRule($moduleCode, array $node, array $notGeneratedEntityItem)
    {
        if (!array_key_exists('config', $node) || count($node['config']) === 0) {
            return true;
        }
        $attributeFieldsMap = ModuleService::getInstance()->getModuleAttributeCodeFieldsMap($moduleCode);
        $attributeFieldsMap = array_flip($attributeFieldsMap);
        $isMatch = true;
        // config 里是or => and的双层配置
        foreach ($node['config'] as $rules) {

            $isMatch = true;
            foreach ($rules as $rule) {
                if (!isset($rule['attribute_key']) || !isset($rule['attribute_values'])) {
                    // 规则内的条件不合法 直接跳过
                    continue;
                }
                $attributeKey = $rule['attribute_key'];
                $attributeValues = $rule['attribute_values'];
                $field = $attributeFieldsMap[$attributeKey] ?? null;
                if (empty($field) || !array_key_exists($field, $notGeneratedEntityItem)) {
                    // 当前实体没有这个属性 或者属性字段为空
                    $isMatch = false;
                    break;
                }
                if (!in_array($notGeneratedEntityItem[$field], $attributeValues)) {
                    // 属性不在规则里
                    $isMatch = false;
                    break;
                }
            }
            /**
             * 经过一轮规则判断如果还是true 那么就说明匹配上规则了 就可以break 返回了
             * 如果是false 那么说明规则不匹配 匹配吓一条规则
             */
            if ($isMatch === true) {
                break;
            }
        }
        return $isMatch;
    }

    /**
     * 获取多个实体任务的属性关联字段
     * @param $entityList
     * @param $attributeRuleMapByCode
     * @param $taskList
     * @return array
     */
    public function multipleGenerateWorkflowStepDocAttrStr($entityList, $attributeRuleMapByCode, $taskList)
    {
        $entityJsonMap = [];
        $stepWorkflowIds = [];
        $entityStepWorkflowMap = [];
        foreach ($entityList as $entityItem) {
            $entityJsonMap[$entityItem['id']] = json_decode($entityItem['json'], true);
            if (!empty($entityItem['step_workflow_id'])) {
                $stepWorkflowIds[$entityItem['step_workflow_id']] = $entityItem['step_workflow_id'];
                $entityStepWorkflowMap[$entityItem['id']] = $entityItem['step_workflow_id'];
            }
        }
        $taskEntityMap = array_column($taskList, null, 'id');

        $workflowsData = model(StepWorkflowModel::class)->field('id,config,step_workflow_config,project_id')->where(['id' => ['IN', join(',', $stepWorkflowIds)]])->select();
        $workflowsMap = array_column($workflowsData, null, "id");
        $attrKeys = [];
        $taskUseAttrKeys = [];
        foreach ($taskList as $taskItem) {
            //任务对应 实体的工序流匹配
            if (isset($entityStepWorkflowMap[$taskItem['entity_id']]) && isset($workflowsMap[$entityStepWorkflowMap[$taskItem['entity_id']]])) {

                $workflowsConfig = json_decode($workflowsMap[$entityStepWorkflowMap[$taskItem['entity_id']]]['step_workflow_config'], true);
                foreach ($workflowsConfig['nodes'] as $nodeList) {
                    foreach ($nodeList as $node) {
                        if (!empty($node['id']) && $node['id'] == $taskItem['step_id'] && !empty($node['config'])) {
                            foreach ($node['config'] as $rules) {
                                foreach ($rules as $rule) {
                                    if (empty($taskUseAttrKeys[$taskItem['id']])) {
                                        $taskUseAttrKeys[$taskItem['id']] = [$rule['attribute_key'] => $rule['attribute_key']];
                                    } else {
                                        $taskUseAttrKeys[$taskItem['id']][$rule['attribute_key']] = $rule['attribute_key'];
                                    }
                                    if (!in_array($rule['attribute_key'], $attrKeys)) {
                                        $attrKeys[] = $rule['attribute_key'];
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        // 查询当前工序引用属性名称
        $attrName = model(AttributeModel::class)->field('name,code')->where(['code' => ['IN', join(',', $attrKeys)]])->select();
        $attrNameMap = array_column($attrName, 'name', 'code');
        // 组装
        $taskAttr = [];
        foreach ($taskUseAttrKeys as $taskId => $useAttrKeys) {
            // 按照数值升序排序 按照固定规则组合
            if (!empty($taskEntityMap[$taskId])) {
                $taskEntityMapEntityId = $taskEntityMap[$taskId]['entity_id'];
                $taskEntityMapEntityModuleId = $taskEntityMap[$taskId]['entity_module_id'];
                sort($useAttrKeys);
                foreach ($useAttrKeys as $currentUseAttrKey) {
                    // 可能这个实体 没有这个属性 那么就跳过这个属性
                    if (!empty($attrNameMap[$currentUseAttrKey]) && !empty($attributeRuleMapByCode[$taskEntityMapEntityModuleId][$currentUseAttrKey])
                        && !empty($entityJsonMap[$taskEntityMapEntityId][$attributeRuleMapByCode[$taskEntityMapEntityModuleId][$currentUseAttrKey]['field']])
                    ) {
                        $taskAttr[$taskId][] = $attrNameMap[$currentUseAttrKey] . ":" . $entityJsonMap[$taskEntityMapEntityId][$attributeRuleMapByCode[$taskEntityMapEntityModuleId][$currentUseAttrKey]['field']];
                    }
                }
            }
        }

        foreach ($taskAttr as $taskId => $taskAttrItem) {
            $taskAttr[$taskId] = join("-", $taskAttrItem);
        }

        return $taskAttr;
    }

    /**
     * 获得多个工作流
     * @param $filter
     * @param $field
     * @return mixed
     */
    public function getList($filter, $field = '*')
    {
        $stepWorkflowModel = model(StepWorkflowModel::class);
        $returnData = $stepWorkflowModel->where($filter)
            ->field($field)
            ->select();
        if (empty($returnData)) {
            return [];
        }
        return $returnData;
    }

    /**
     * 查询工序流某个环节下的工序列表
     * @param $stepWorkflowId
     * @param $stepCategoryId
     * @return array|false|mixed|string|null
     */
    public function getWorkFlowStepCategoryStepList($stepWorkflowId, $stepCategoryId)
    {
        if (empty($stepWorkflowId)) {
            return [];
        }
        $workFlow = model(StepWorkflowModel::class)->where(['id' => $stepWorkflowId])->field('JSON_UNQUOTE(JSON_EXTRACT(config,"$.nodes")) as nodes')->find();
        if (empty($workFlow)) {
            return [];
        }
        $workFlowNodes = json_decode($workFlow['nodes'], true);
        if (empty($workFlowNodes)) {
            return [];
        }
        $stepIds = [];
        foreach ($workFlowNodes as $node) {
            $stepIds[] = $node[0]['id'];
        }
        if (empty($stepIds)) {
            return [];
        }
        return StepService::getInstance()->getList(['id' => ['IN', join(',', $stepIds)], 'step_category_id' => $stepCategoryId], '*');
    }

    /**
     * 获取实体工序流id
     * @param $projectId
     * @param $stepWorkFlowCode
     * @return int|mixed
     */
    public function getEntityWorkFlowId($projectId, $stepWorkFlowCode)
    {
        $stepWorkflowId = 0;
        if (empty($projectId) || empty($stepWorkFlowCode)) {
            return $stepWorkflowId;
        }
        // 如果当前项目配置了工序流,就取当前项目配置工序流,没有就取默认("平台")配置工序流
        $project = model(ProjectModel::class)->find($projectId);
        $stepWorkflowData = model(StepWorkflowModel::class)
            ->where(['code' => $stepWorkFlowCode, 'is_enable' => StepWorkflowModel::OPEN_STEP_WORK_FLOW, 'project_template_id' => $project['project_template_id'] ?? 0])
            ->where(['project_id' => $project['id'] ?? 0])
            ->field('id')
            ->find();
        if (!empty($stepWorkflowData['id'])) {
            $stepWorkflowId = $stepWorkflowData['id'];
        }
        if (empty($stepWorkflowId)) {
            $defaultStepWorkflowData = model(StepWorkflowModel::class)
                ->where(['code' => $stepWorkFlowCode, 'is_enable' => StepWorkflowModel::OPEN_STEP_WORK_FLOW, 'project_template_id' => 0])
                ->field('id')
                ->find();
            if (!empty($defaultStepWorkflowData['id'])) {
                $stepWorkflowId = $defaultStepWorkflowData['id'];
            }
        }
        return $stepWorkflowId;
    }

    /**
     * 获取提出阶段列表
     * @param $projectId [项目id]
     * @param $page [分页]
     * @param string $episodeCode 集数code
     * @param string $moduleCode 模块code
     * @param int $reviewFeedbackId 需修改需求id
     * @return array|false|mixed|string
     */
    public function getEnableStepWorkflowStageList($projectId, $page, string $episodeCode = '', string $moduleCode = '', int $reviewFeedbackId = 0)
    {
        $stageList = model(StepWorkflowModel::class)
            ->field([
                "stage.id",
                "stage.name",
                "stage.order_number",
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.demand_display_status')) as demand_display_status",   // 是否在需求单中显示
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.standard_append_number')) as standard_append_number", // 标准新增的限制次数
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.join_demand_stage_rule')) as join_demand_stage_rule", // 是否需要校验规则
                "JSON_UNQUOTE(JSON_EXTRACT(stage.json, '$.task_step_id')) as task_step_id" // 设置的工序id
            ])
            ->join('stage on stage.id = step_workflow.stage_id', 'left')
            ->where([
                "step_workflow.project_id" => $projectId,
                "step_workflow.is_enable" => "yes",
                "stage.json->>'$.demand_display_status'" => StageModel::DEMAND_DISPLAY_STATUS_YES // 只获取在需求单展示的阶段
            ])
            ->group("stage.id")
            ->order('stage.order_number ASC')
            ->page(...$page)
            ->select();

        // 不传集数返回默认列表，不进行二次处理
        return empty($episodeCode) ? $stageList : $this->dealStageList($projectId, $episodeCode, $moduleCode, $stageList, $reviewFeedbackId);
    }

    /**
     * 处理阶段列表，标识阶段的可选性和新增类型
     * @param $projectId [项目id]
     * @param $episodeCode [集数code]
     * @param $moduleCode [模块code]
     * @param $stageList [提出阶段id列表]
     * @return mixed
     */
    private function dealStageList($projectId, $episodeCode, $moduleCode, $stageList, $reviewFeedbackId)
    {
        $reviewFeedbackInfo = [];
        if (!empty($reviewFeedbackId)) {
            $reviewFeedbackInfo = model(ReviewFeedbackModel::class)->field(['id', 'stage_id', 'standard_append'])->where(['id' => $reviewFeedbackId])->find();
        }
        // 获取当前集所有走完的标准新增的阶段id
        $standardAppendStage = DemandOrderService::getInstance()->getStandardAppendStageIdsByEpisodeCode($projectId, $episodeCode, $moduleCode);
        // 获取当前集最新的阶段
        $currentStageInfo = DemandOrderService::getInstance()->getCurrentStage($projectId, $episodeCode, $moduleCode);

        // 获取需要判断该工序下的任务是否完成的工序id
        $taskStepIds = [];
        foreach ($stageList as $stageInfo) {
            if (!empty($stageInfo['task_step_id'])) {
                $taskStepIds[] = $stageInfo['task_step_id'];
            }
        }

        // 根据工序id进行分组
        $notFinalTaskStepGroup = DemandOrderService::getInstance()->getNotFinalTaskStepMap($projectId, $episodeCode, $taskStepIds);

        foreach ($stageList as &$item) {
            // 默认设置可添加标准和非标准需求
            $item['standard_append'] = ReviewFeedbackModel::STANDARD_APPEND_YES;

            if ($item['join_demand_stage_rule'] == StageModel::JOIN_DEMAND_STAGE_RULE_NO) {
                // 1. 如果设置不参加阶段规则校验，当前可添加标准和非标准需求
                $item['standard_append'] = ReviewFeedbackModel::STANDARD_APPEND_YES;
            } else {
                // 2. 如果设置参加阶段规则校验，需要校验规则
                $item['standard_append'] = $this->checkStageRuleAndGetStandardAppend($item, $currentStageInfo, $notFinalTaskStepGroup, $standardAppendStage, $reviewFeedbackInfo);
            }
        }

        return $stageList;
    }

    /**
     * 校验规则以及获取需求新增类型
     * @param array $stageInfo 阶段信息
     * @param array $currentStageInfo 当前最新的阶段信息(标准新增的需求)
     * @param array $notFinalTaskStepGroup 未完成的任务
     * @param array $standardAppendStage 标准新增的阶段id信息
     * @return string
     */
    private function checkStageRuleAndGetStandardAppend(array $stageInfo, array $currentStageInfo, array $notFinalTaskStepGroup, array $standardAppendStage, array $reviewFeedbackInfo)
    {
        // 需求单存在标准新增需求，并且已走完的阶段不能选择标准新增，只能选择非标准新增
        if (!empty($currentStageInfo) && $stageInfo['order_number'] < $currentStageInfo['order_number']) {
            $standardAppend = ReviewFeedbackModel::STANDARD_APPEND_NO;
        } else {

            // 未走完的阶段
            if (
                // 设置过工序id判断条件
                !empty($stageInfo['task_step_id']) &&
                // 该工序下有任务
                isset($notFinalTaskStepGroup[$stageInfo['task_step_id']]) &&
                // 有未完成的任务
                empty($notFinalTaskStepGroup[$stageInfo['task_step_id']])
            ) {
                // 设置过工序id判断条件 && 该工序下有任务 && 有未完成的任务  该阶段只能添加非标准需求
                $standardAppend = ReviewFeedbackModel::STANDARD_APPEND_NO;
            } else {
                if ($stageInfo['standard_append_number'] < 0) {
                    // 1. 标准新增的次数小于0(不限制次数)，当前可添加标准和非标准需求
                    $standardAppend = ReviewFeedbackModel::STANDARD_APPEND_YES;
                } else {
                    // 2. 标准新增的次数大于0(限制次数)
                    $stageCountMap = array_count_values($standardAppendStage['standard_append_stage_ids']);  // 统计每个阶段的标准新增次数
                    // 如果该阶段存在标准新增需求，并且次数已超过设置标准新增限制的次数，那当前只能添加非标准需求，否则当前可添加标准和非标准需求
                    $standardAppend = (isset($stageCountMap[$stageInfo['id']]) && $stageCountMap[$stageInfo['id']] >= $stageInfo['standard_append_number']) ? ReviewFeedbackModel::STANDARD_APPEND_NO : ReviewFeedbackModel::STANDARD_APPEND_YES;
                }
            }

        }

        // 需要判断修改的情况，如果是旧数据是标准需求，那需改的时候还是能下发标准或者非标准需求
        if (
            !empty($reviewFeedbackInfo) &&  // 修改的需求
            $reviewFeedbackInfo['stage_id'] == $stageInfo['id'] && // 与旧数据的环节相同
            $standardAppend == ReviewFeedbackModel::STANDARD_APPEND_NO && // 被校验为非标准任务
            $reviewFeedbackInfo['standard_append'] == ReviewFeedbackModel::STANDARD_APPEND_YES // 旧数据的类型是标准需求
        ) {
            $standardAppend = ReviewFeedbackModel::STANDARD_APPEND_YES;
        }

        return $standardAppend;
    }
}
